feat(dock): add app launch event reporting for taskbar icons#1606
feat(dock): add app launch event reporting for taskbar icons#1606Ivy233 wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Ivy233 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
35405ee to
0b79013
Compare
|
TAG Bot New tag: 2.0.43 |
0b79013 to
2e0b988
Compare
deepin pr auto review这份代码实现了一个应用启动时长上报器,通过 D-Bus 查询应用实例信息,结合 但在语法逻辑、代码质量、性能和安全性方面存在一些需要改进的地方。以下是详细的审查意见: 1. 语法与逻辑问题
2. 代码性能
3. 代码安全
4. 代码质量与可维护性
改进后的代码示例针对以上核心问题,以下是修改后的 // ... 头部保持不变,建议修改年份 ...
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
namespace {
// ... 常量定义增加 ...
constexpr auto kAmService = "org.desktopspec.ApplicationManager1";
constexpr auto kApplicationIface = "org.desktopspec.ApplicationManager1.Application";
constexpr auto kInstanceIface = "org.desktopspec.ApplicationManager1.Instance";
constexpr int kLinglongCacheTTLSeconds = 1800;
constexpr int kDebCacheTTLSeconds = 1800;
constexpr int kDbusTimeoutMs = 1000;
constexpr int kSubprocessTimeoutMs = 3000;
QList<InstanceInfo> queryInstances(const QString &desktopId)
{
QList<InstanceInfo> result;
auto appPath = QStringLiteral("/org/desktopspec/ApplicationManager1/%1").arg(escapeToObjectPath(desktopId));
QDBusInterface appIface(QString::fromUtf8(kAmService),
appPath,
QStringLiteral("org.freedesktop.DBus.Properties"),
QDBusConnection::sessionBus());
appIface.setTimeout(kDbusTimeoutMs);
QDBusReply<QVariant> reply = appIface.call(QStringLiteral("Get"),
QString::fromUtf8(kApplicationIface),
QStringLiteral("Instances"));
if (!reply.isValid()) {
qCDebug(launchDurationReporter) << "[DockIconTiming] queryInstances failed for" << desktopId << ":" << reply.error().message();
return result;
}
const auto paths = qdbus_cast<QList<QDBusObjectPath>>(reply.value());
for (const auto &path : paths) {
QDBusInterface instIface(QString::fromUtf8(kAmService),
path.path(),
QStringLiteral("org.freedesktop.DBus.Properties"),
QDBusConnection::sessionBus());
instIface.setTimeout(kDbusTimeoutMs);
InstanceInfo info;
info.instanceId = path.path().section(QLatin1Char('/'), -1);
// 优化:使用 QDBusReply 简化提取逻辑
QDBusReply<QVariant> launchTypeReply = instIface.call(QStringLiteral("Get"),
QString::fromUtf8(kInstanceIface),
QStringLiteral("LaunchType"));
if (launchTypeReply.isValid()) {
info.launchType = launchTypeReply.value().toString();
}
if (info.launchType.isEmpty()) {
info.launchType = QStringLiteral("unknown");
}
result.append(info);
}
return result;
}
QHash<QString, QString> loadAllLinglongVersions()
{
QHash<QString, QString> result;
QProcess proc;
// 建议:如果 ll-cli 支持 --json,请使用 JSON 解析代替字符串分割
proc.start(QStringLiteral("ll-cli"), {QStringLiteral("list"), QStringLiteral("--type"), QStringLiteral("app")});
if (!proc.waitForFinished(kSubprocessTimeoutMs)) {
qCWarning(launchDurationReporter) << "ll-cli list timeout";
proc.kill();
proc.waitForFinished();
return result;
}
if (proc.exitCode() != 0) {
qCWarning(launchDurationReporter) << "ll-cli list failed, exitCode:" << proc.exitCode();
return result;
}
QString output = QString::fromUtf8(proc.readAllStandardOutput());
QStringList lines = output.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
// Skip header line
for (int i = 1; i < lines.size(); ++i) {
// 优化:使用正则匹配连续空格,防止单元格内包含空格导致错位
QStringList columns = lines[i].simplified().split(QRegularExpression("\\s+"));
if (columns.size() >= 3) {
QString name = columns[1];
QString version = columns[2];
if (!name.isEmpty()) {
result.insert(name, version);
}
}
}
return result;
}
// 正则表达式验证包名合法性,防止注入或异常字符
static bool isValidDesktopId(const QString &desktopId) {
static QRegularExpression validNameRegex("^[a-z0-9][a-z0-9+.-]+$");
return validNameRegex.match(desktopId).hasMatch();
}
} // namespace
namespace dock {
// ... 构造和析构保持不变 ...
void LaunchDurationReporter::reportWindowAppeared(const QString &desktopId)
{
if (desktopId.isEmpty() || !isValidDesktopId(desktopId)) {
return;
}
// 不需要接收 future 则不接收,避免 Q_UNUSED
QtConcurrent::run(&m_workerPool, [this, desktopId]() {
auto instances = queryInstances(desktopId);
QString uniqueId;
QString launchType = QStringLiteral("unknown");
if (!instances.isEmpty()) {
const auto &latest = instances.constLast();
uniqueId = latest.instanceId;
launchType = latest.launchType;
}
if (uniqueId.isEmpty()) {
return;
}
QString version;
QString pakType;
{
QMutexLocker locker(&m_cacheMutex);
qint64 currentTime = QDateTime::currentSecsSinceEpoch();
if ((currentTime - m_linglongCacheTime) > kLinglongCacheTTLSeconds) {
m_linglongCache = loadAllLinglongVersions();
m_linglongCacheTime = currentTime;
}
if (m_linglongCache.contains(desktopId)) {
version = m_linglongCache.value(desktopId);
pakType = QStringLiteral("linglong");
} else if (m_debCache.contains(desktopId)) {
const auto &entry = m_debCache.value(desktopId);
if ((currentTime - entry.timestamp) <= kDebCacheTTLSeconds) {
version = entry.version;
pakType = entry.pakType;
}
}
}
if (pakType.isEmpty()) {
QProcess proc;
proc.start(QStringLiteral("dpkg-query"), {QStringLiteral("-W"), QStringLiteral("-f=${Version}"), desktopId});
proc.waitForFinished(kDbusTimeoutMs); // 复用超时常量
if (proc.exitCode() == 0) {
version = QString::fromUtf8(proc.readAllStandardOutput()).trimmed();
pakType = QStringLiteral("deb");
} else {
qCDebug(launchDurationReporter) << "dpkg-query failed for" << desktopId << "exitCode:" << proc.exitCode();
pakType = QStringLiteral("unknown");
}
QMutexLocker locker(&m_cacheMutex);
m_debCache.insert(desktopId, {version, pakType, QDateTime::currentSecsSinceEpoch()});
}
QMetaObject::invokeMethod(this, [this, desktopId, uniqueId, launchType, version, pakType]() {
doReport(desktopId, uniqueId, launchType, version, pakType);
}, Qt::QueuedConnection);
});
}
// ... doReport 保持不变 ...
} // namespace dock |
Use AM.Identify(pidfd) for precise per-window instance mapping, read X-linglong from desktop files, and query dpkg/linglong for package version info. Report the data via DDE EventLogger (event ID 1000610003). 使用 pidfd 精准匹配窗口与 AM 实例,从桌面文件读取玲珑包名, 通过 dpkg/玲珑查询包版本信息,并通过 DDE EventLogger 上报数据。 Log: 新增任务栏图标启动时长上报 PMS: TASK-389405
2e0b988 to
31355d0
Compare
|
TAG Bot New tag: 2.0.44 |
|
TAG Bot New tag: 2.0.45 |
Log: Report app launch events when taskbar icons appear for analytics
Influence:
feat(dock): 添加任务栏图标出现时的应用启动事件上报
Log: 任务栏图标出现时上报应用启动事件用于分析
Influence:
PMS: TASK-389405